﻿using System;
using System.Device.Location;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Maps.Controls;
using Microsoft.Phone.Shell;
using Windows.Devices.Geolocation;
using Chenglin.WPMyStep.Resources;

namespace Chenglin.WPMyStep.Controls
{
    public partial class TrackControl : UserControl
    {
        /// <summary>
        /// Get or set the page which contains the control.
        /// </summary>
        internal PhoneApplicationPage Page
        {
            get;
            set;
        }

        private MapLayer _mapLayer;
        private MapOverlay _currentLocationOverlay;
        private MapPolyline _mapPolyine;
        private bool _isTracking;

        private const int MaxLocationsToDisplay = 64;

        public TrackControl()
        {
            InitializeComponent();

            Microsoft.Phone.Maps.MapsSettings.ApplicationContext.ApplicationId = App.MapApplicationId;
            Microsoft.Phone.Maps.MapsSettings.ApplicationContext.AuthenticationToken = App.MapAuthenticationToken;
            mapControl.Center = new GeoCoordinate(39.9038925170898d, 116.394569396973d);
            Loaded += MainPage_Loaded;
            Unloaded += MainPage_Unloaded;

            _mapLayer = new MapLayer();
            _currentLocationOverlay = new MapOverlay { PositionOrigin = new Point(0.5, 0.5) };
            _mapLayer.Add(_currentLocationOverlay);

            _mapPolyine = new MapPolyline();
            _mapPolyine.StrokeThickness = 5;
            _mapPolyine.StrokeColor = (Color)Application.Current.Resources["PhoneAccentColor"];
            mapControl.MapElements.Add(_mapPolyine);

            mapControl.Layers.Add(_mapLayer);
        }

        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            BuildApplicationBar();

            // Initialize the location tracker
            var trakcer = LocationTracker.Instance;
            trakcer.PositionChanged += Geolocator_PositionChanged;
            trakcer.StatusChanged += Geolocator_StatusChanged;
        }

        private void MainPage_Unloaded(object sender, RoutedEventArgs e)
        {
            var trakcer = LocationTracker.Instance;
            trakcer.PositionChanged -= Geolocator_PositionChanged;
            trakcer.StatusChanged -= Geolocator_StatusChanged;
        }

        private void Geolocator_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
        {
            if (App.RunningInBackground)
            {
                return;
            }

            switch (args.Status)
            {
                case PositionStatus.Disabled:
                case PositionStatus.NotAvailable:
                    gpsLocationTextBlock.Text = AppResources.Status_NotAvailable;
                    break;

                case PositionStatus.Initializing: gpsLocationTextBlock.Text = AppResources.Status_Initializing; break;
                case PositionStatus.NoData: gpsLocationTextBlock.Text = AppResources.Status_NoData; break;
                case PositionStatus.NotInitialized: gpsLocationTextBlock.Text = AppResources.Status_NotInitialized; break;
                case PositionStatus.Ready: gpsLocationTextBlock.Text = AppResources.Status_Initialized; break;
            }
        }

        private void Geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
        {
            if (!App.RunningInBackground)
            {
                var coordinate = args.Position.Coordinate;
                Dispatcher.BeginInvoke(() =>
                {
                    gpsLocationTextBlock.Text = string.Format("{0}, {1}", coordinate.Longitude, coordinate.Latitude);

                    var c = coordinate.ToGeoCoordinate();

                    Image image = new Image();
                    image.Stretch = Stretch.None;
                    image.Source = new BitmapImage(new Uri("/Assets/Mark.png", UriKind.Relative));
                    _currentLocationOverlay.Content = image;

                    if (_mapPolyine.Path.Count > MaxLocationsToDisplay)
                    {
                        _mapPolyine.Path.RemoveAt(0);
                    }
                    _mapPolyine.Path.Add(c);

                    _currentLocationOverlay.GeoCoordinate = c;
                    this.mapControl.Center = c;
                    this.mapControl.SetView(c, this.mapControl.ZoomLevel, MapAnimationKind.Linear);
                });


            }
        }

        /// <summary>
        /// Allow the user to toggle opting in and out of location with an ApplicationBar menu item. 
        /// </summary>
        private void BuildApplicationBar()
        {
            if (Page == null)
            {
                throw new InvalidOperationException("The Page property has not been initialized.");
            }

            // Set the page's ApplicationBar to a new instance of ApplicationBar. 
            Page.ApplicationBar = new ApplicationBar();

            // Button for start/stop gps device
            if (!_isTracking)
            {
                ApplicationBarIconButton appBarButton1 = new ApplicationBarIconButton(new Uri("/Assets/Foot.png", UriKind.Relative));
                appBarButton1.Text = AppResources.StartGPSButtonText;
                appBarButton1.Click += AppBarButton_StartStopClick;
                Page.ApplicationBar.Buttons.Add(appBarButton1);
            }
            else
            {
                ApplicationBarIconButton appBarButton1 = new ApplicationBarIconButton(new Uri("/Assets/Stop.png", UriKind.Relative));
                appBarButton1.Text = AppResources.StopGPSButtonText;
                appBarButton1.Click += AppBarButton_StartStopClick;
                Page.ApplicationBar.Buttons.Add(appBarButton1);
            }

            // Button for go to history
            ApplicationBarIconButton appBarButton3 = new ApplicationBarIconButton(new Uri("/Assets/GotoHistory.png", UriKind.Relative));
            appBarButton3.Text = AppResources.GotoHistoryButtonText;
            appBarButton3.Click += delegate { Page.NavigationService.Navigate(new Uri("/HistoryPage.xaml", UriKind.Relative)); };
            Page.ApplicationBar.Buttons.Add(appBarButton3);

            var zoomInMenu = new ApplicationBarMenuItem { Text = AppResources.ZoomIn };
            zoomInMenu.Click += delegate { this.mapControl.ZoomLevel = (int)Math.Min(20, this.mapControl.ZoomLevel + 1); };
            Page.ApplicationBar.MenuItems.Add(zoomInMenu);

            var zoomOutMenu = new ApplicationBarMenuItem { Text = AppResources.ZoomOut };
            zoomOutMenu.Click += delegate { this.mapControl.ZoomLevel = (int)Math.Max(1, this.mapControl.ZoomLevel - 1); };
            Page.ApplicationBar.MenuItems.Add(zoomOutMenu);
        }

        private void AppBarButton_StartStopClick(object sender, EventArgs e)
        {
            ApplicationBarIconButton button = (ApplicationBarIconButton)sender;
            if (button.Text == AppResources.StartGPSButtonText)
            {
                // start to track gps location
                LocationTracker.Instance.Start();

                button.IconUri = new Uri("/Assets/Stop.png", UriKind.Relative);
                button.Text = AppResources.StopGPSButtonText;

                _isTracking = true;
                this.gpsLocationTextBlock.Text = AppResources.Status_Initializing;
            }
            else
            {
                // stop tracking gps location
                if (MessageBoxResult.OK == MessageBox.Show(AppResources.ConfirmStopText, AppResources.Confirmation, MessageBoxButton.OKCancel))
                {
                    button.IconUri = new Uri("/Assets/Foot.png", UriKind.Relative);
                    button.Text = AppResources.StartGPSButtonText;
                    this.gpsLocationTextBlock.Text = AppResources.Status_Stopped;

                    // save all the locations recorded!
                    var locations = LocationTracker.Instance.Stop();
                    if (locations.Length > 1)
                    {
                        try
                        {
                            StepRecord record = new StepRecord { Locations = locations };
                            record.Save();
                        }
                        catch (Exception)
                        {
                            // Ignore all exceptions here
                        }
                    }

                    _isTracking = false;
                    this.gpsLocationTextBlock.Text = AppResources.Status_Stopped;
                }
            }
        }
    }
}
